package jmine.tec.report.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import jmine.tec.report.DataColumn;
import jmine.tec.report.metadata.ColumnMetaData;
import jmine.tec.report.metadata.ParameterDefinition;
import jmine.tec.report.metadata.impl.UnmodifiableColumnMetaData;

/**
 * DataColumn simples.
 * 
 * @author julien
 * @author gigante
 */
public class SimpleDataColumn extends AbstractDataColumn implements DataColumn, Serializable {

    private static final long serialVersionUID = -1268738481512009985L;

    private ColumnMetaData metaData;

    private boolean sortable = true;

    private final Map<String, Object> defaultParameterValues = new HashMap<String, Object>();

    /**
     * C'tor
     * 
     * @param key chave da coluna para
     * @param name nome da coluna - usado como label
     * @param metaData o {@link ColumnMetaData}
     * @param hashMap the default parameter values *
     * @param otherParams other parameters to append to this column metadata
     */
    public SimpleDataColumn(final String key, final String name, final ColumnMetaData metaData,
            final Map<String, Object> hashMap, final ParameterDefinition... otherParams) {
        super(key, name);
        this.metaData = new UnmodifiableColumnMetaData(key, name, metaData, otherParams);
        if (hashMap != null) {
            final Set<Entry<String, Object>> entrySet = hashMap.entrySet();
            for (Entry<String, Object> entry : entrySet) {
                this.addDefaultParameterValue(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * C'tor
     * 
     * @param key the column key
     * @param name the column name
     * @param metaData the base metadata
     * @param otherParams other parameters to append to this column metadata
     */
    public SimpleDataColumn(final String key, final String name, final ColumnMetaData metaData,
            final ParameterDefinition... otherParams) {
        super(key, name);
        this.metaData = new UnmodifiableColumnMetaData(key, name, metaData, otherParams);
    }

    /**
     * C'tor
     * 
     * @param key String
     * @param name String
     * @param params Parameters
     */
    public SimpleDataColumn(final String key, final String name, final ParameterDefinition... params) {
        super(key, name);
        this.metaData = new UnmodifiableColumnMetaData(key, name, params);
    }

    /**
     * C'tor
     * 
     * @param meta the {@link ColumnMetaData}
     */
    public SimpleDataColumn(final ColumnMetaData meta) {
        super(meta.getKey(), meta.getLabel());
        this.metaData = new UnmodifiableColumnMetaData(meta);
    }

    /**
     * Devolve o {@link ColumnMetaData} associado
     * 
     * @return {@link ColumnMetaData}
     * @see br.com.maps.util.report.DataColumn#getMetaData()
     */
    public final ColumnMetaData getMetaData() {
        return this.modifyMetaDataInternal(this.metaData);
    }

    /**
     * @param metaData the metaData to set
     */
    public void setMetaData(final ColumnMetaData metaData) {
        this.metaData = metaData;
    }

    /**
     * Retorna um view deste DataColumn
     * 
     * @param params os par�metros
     * @return DataColumn
     */
    @Override
    public SimpleDataColumn getView(final Map<String, Object> params) {
        return new SimpleDataColumn(this.getKey(), this.getName(), new UnmodifiableColumnMetaData(this.getMetaData()),
                this.getDefaultParameterValues());
    }

    /**
     * Metodo para ser sobrescrito por subclasses para que elas modifiquem o {@link ColumnMetaData} ou devolvam uma nova instancia.
     * <p>
     * É recomendado que subclasses mantenham os atributos 'key' e 'name' do ColumnMetaData passado como parametro para manter consistencia.
     * <p>
     * A implementacao desta classe apenas devolve a {@link ColumnMetaData} passada como parametro
     * 
     * @param original o {@link ColumnMetaData} original
     * @return {@link ColumnMetaData}
     */
    protected ColumnMetaData modifyMetaDataInternal(final ColumnMetaData original) {
        return original;
    }

    /**
     * @return the sortable
     */
    public boolean isSortable() {
        return this.sortable;
    }

    /**
     * @param sortable the sortable to set
     */
    public void setSortable(final boolean sortable) {
        this.sortable = sortable;
    }

    /**
     * @return to {@link String}
     */
    @Override
    public String toString() {
        return "name: " + this.getName() + ", key: " + this.getKey();
    }

    /**
     * Pega o valor default para um parametro, se houver.
     * 
     * @param parameterKey {@link String} a chave do parametro
     * @return {@link Object}
     */
    public Object getDefaultParameterValue(final String parameterKey) {
        return this.defaultParameterValues.get(parameterKey);
    }

    /**
     * @return the defaultParameterValues
     */
    public Map<String, Object> getDefaultParameterValues() {
        return this.defaultParameterValues;
    }

    /**
     * Adiciona um valor default ao parametro.
     * 
     * @param parameterKey {@link String}
     * @param parameterValue {@link String}
     */
    protected void addDefaultParameterValue(final String parameterKey, final Object parameterValue) {
        if (this.getMetaData().hasParameter(parameterKey)) {
            this.defaultParameterValues.put(parameterKey, parameterValue);
        }
    }

}
